/***********************************************************************************
 * 文件名： bstc.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 *      面向对象设计的升压控制器，便于多路升压控制。升压电路的驱动，通过电压值反馈调整PWM
 * 占空比达到升压，并恒定电压的目的。不要与单例模式的 boost_controller 同时使用。
 *      提供以下功能：
 *          升压输出；
 *          电压调节；
 *          过流保护和通知；
 *          过载通知；
 *          开路保护和通知【未实现】。
 * 修改记录：
 * 	2022/07/15: 初版。 刘言。
***********************************************************************************/
#include "bstc.h"
#include "components\ly_pid\ly_pid.h"
#include "polsys.h"


// 以下是所有对象共用的静态变量

#ifndef POLSYS_LITE
static polsys_task_t sTask;
static bool sTaskInited = false;
static u8 sAmountObj = 0;
static bstc_t sObjs[_BSTC_MAX_OBJS];
static void Loop();
#endif


void BSTC_evNewFBV(bstc_t this, bstc_adv_t adv)
{
    if(this->mRun)
    {
        s16 target_pwm = (s16)PID_getChange((ly_pid_t)this, this->mTargetADV, adv) + this->mPwmValue;
        if(target_pwm < 0) this->mPwmValue = 0;
        else if(target_pwm > this->mMaxPwmValue)this->mPwmValue = this->mMaxPwmValue;
        else this->mPwmValue = target_pwm;
        this->SetPwm(this->mPwmValue);

        this->mNowADV = adv;
    }
}

// 开关（MOS）管电流过大事件，由外部调用，通知 BSTC。
// 一般是由电压比较器或者ADC产生中断在中断中调用
void BSTC_evOverCurrent(bstc_t this)
{
    if(this->mOcCount >= this->mOcAllowCount)
    {
        BSTC_stop(this);
        this->mEvent |= BSTC_EV_SHORT_OUT;
    }
    this->mOcCount++;
}

void BSTC_init(bstc_t this, bstc_init_param_t init_param)
{
    PID_init((ly_pid_t)this, init_param->kp, init_param->ki, init_param->kd); // 初始化父类
    this->EventCallBack = init_param->EventCallBack;
    this->SetPwm = init_param->SetPwm;
    this->mNowADV = 0;
    this->mOcCount = 0;
    this->mPwmValue = 0;
    this->mRun = false;
    this->mEvent = BSTC_EV_NULL;
    this->mMaxPwmValue = init_param->MaxPwmValue;
    this->mOcAllowCount = init_param->OcAllowCount;
    this->mTargetADV = init_param->TargetADV;
    // this->InitAdc = init_param->InitAdc;      只在这里直接调用一次就好了，不用保存
    this->RunAdc = init_param->RunAdc;
    this->StopAdc = init_param->StopAdc;
    init_param->InitAdc();
    // this->InitPwm = init_param->InitPwm;  只在这里直接调用一次就好了，不用保存
    init_param->InitPwm();
    sObjs[sAmountObj] = this;   // 保存到对象列表
    sAmountObj++;               // 已存在的对象总数
#ifndef POLSYS_LITE
    if(sTaskInited == false)
    {
        Polsys_TaskInit(&sTask, Loop, 10);
        sTaskInited = true;
    }
#endif
}

void BSTC_start(bstc_t this, bstc_pwmv_t start_pwm)
{
    PID_reset((ly_pid_t)this);
    this->mOcCount = 0;
    this->mPwmValue = start_pwm;
    this->mRun = true;
    this->mEvent = BSTC_EV_NULL;
    this->SetPwm(this->mPwmValue);
    this->RunAdc();
}

void BSTC_stop(bstc_t this)
{
    this->StopAdc();
    this->SetPwm(0);
    this->mRun = false;
}

#ifdef _BSTC_USE_EXT_CAL_ADV

bstc_adv_t BSTC_getNowADV(bstc_t this)
{
    return this->mNowADV;
}
#else
u16 BSTC_getNowVoltage(bstc_t this)
{
    u16 v;
    //v = mNowADV * (u32)((float)_BSTC_ADC_VREF * (_BSTC_FBRH + _BSTC_FBRL) / _BSTC_FULL_ADV  / _BSTC_FBRL * 1000) / 1000;
    v = mNowADV * (u32)_BSTC_ADC_VREF * (_BSTC_FBRH + _BSTC_FBRL) / _BSTC_FULL_ADV  / _BSTC_FBRL;
    return v;
}
#endif

// 以下是内部函数

#ifdef POLSYS_LITE
// 建议间隔10ms运行一次
void BSTC_loop()
#else
// 循环处理的任务，间隔10ms会被调用一次
static void Loop()
#endif
{
    u8 i;
    for(i = 0; i < sAmountObj; i++) // 遍历每个对象实例
    {
        if(sObjs[i]->mRun)
        {
            sObjs[i]->mOcCount = 0;
        }
        if(sObjs[i]->mEvent != BSTC_EV_NULL)
        {
            if(sObjs[i]->EventCallBack != NULL)
                sObjs[i]->EventCallBack(sObjs[i]->mEvent); // 调用事件回调，通知异常事件
            sObjs[i]->mEvent = BSTC_EV_NULL;
        }
    }
}
